/**
 * Copyright (C) BFH www.bfh.ch 2011
 * Code written by: Patrick Dobler, Marc Folly
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ch.bfh.ti.kybernetik.engine.controller.lightBulb;

import javax.vecmath.Point2d;
import javax.vecmath.Vector2d;

import ch.bfh.ti.kybernetik.engine.controller.Simulator;
import ch.bfh.ti.kybernetik.engine.model.LightBulb;
import ch.bfh.ti.kybernetik.engine.model.LightSensor;

/**
 * The {@link Simulator} default {@link LightBulbController} implementation
 * 
 */
class DefaultLightBulbControllerImpl implements LightBulbController {

	private final LightBulb lightBulb;

	@Override
	public LightBulb getLightBulb() {
		return lightBulb;
	}

	public DefaultLightBulbControllerImpl(LightBulb lightBulb) {
		this.lightBulb = lightBulb;
	}

	@Override
	public double calculateIntensity(Point2d lightSensorPoint, LightSensor lightSensor, Vector2d lightSensorVector) {

		Vector2d distanceVector = buildLightBulbToPointVector(lightSensorPoint);
		double distance = distanceVector.length();
		if (distance > lightBulb.getMaxRadius()) {
			return 0;
		}
		double intensity = calculateGeneralDistanceLightIntensity(distance);

		// Calculate Licht_Einfallswinkel (lightSensorToLightBulbAngle)
		double lightSensorToLightBulbAngle = calculateLightSensorToLightBulbAngle(lightSensorVector, distanceVector);
		// View Field Area of the Sensor
		double lightSensorViewFieldAngle = lightSensor.getViewFieldSize() / 2;

		if (lightSensorToLightBulbAngle > lightSensorViewFieldAngle) {
			return 0;
		}
		// System.out.println("lightSensorToLightBulbAngle \t" +
		// lightSensorToLightBulbAngle);
		// System.out.println("lightSensorViewFieldAngle \t" +
		// lightSensorViewFieldAngle);
		// System.out.println("intensity normal \t" + intensity);
		// Lineare Abnahmefunktion
		// y = m * x + n
		// y = - (intensity / lightSensorViewFieldAngle ) * Licht_Einfallswinkel
		// + intensity;
		double percentIntensity = -(intensity / lightSensorViewFieldAngle) * lightSensorToLightBulbAngle + intensity;
		// System.out.println("intensity scaled \t" + percentIntensity);
		// out of visible view field
		if (percentIntensity < 0) {
			return 0;
		}

		return percentIntensity;
	}

	public double calculateLightSensorToLightBulbAngle(Vector2d lightSensorVector, Vector2d distanceVector) {
		double lightSensorToLightBulbAngle = Math.toDegrees(distanceVector.angle(lightSensorVector));
		return lightSensorToLightBulbAngle;
	}

	private double calculateGeneralDistanceLightIntensity(double distance) {
		// y = lightBulb.getMaxIntensity() * (lightBulb.getMaxRadius() -
		// distance )^2) / lightBulb.getMaxRadius()^2
		double term1 = ((lightBulb.getMaxRadius() - distance) * (lightBulb.getMaxRadius() - distance)) * lightBulb.getMaxIntensity();
		double term2 = (lightBulb.getMaxRadius() * lightBulb.getMaxRadius());
		double intensity = term1 / term2;
		return intensity;
	}

	private Vector2d buildLightBulbToPointVector(Point2d lightSensorPoint) {
		Vector2d distanceVector = new Vector2d(lightBulb.getX() - lightSensorPoint.getX(), lightBulb.getY() - lightSensorPoint.getY());
		return distanceVector;
	}
}
